﻿using DadayunApi;
using DadayunApi.Model;
using KhtApi.DAL;
using KhtApi.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KhtApi.BLL
{
    public class FormBLL
    {
        private FormDAL dal = null;
        private ReportBLL reportBLL = null;
        public string ErrMsg { get; private set; }
        /// <summary>
        /// 系统返回的响应原始数据
        /// 操作失败时可以查询此信息
        /// </summary>
        public string ResponseJson { get { return dal.ResponseJson; } }
        public FormBLL(AppAuthBase authBase, string baseUri)
        {
            dal = new FormDAL(authBase, baseUri);
            reportBLL = new ReportBLL(authBase, baseUri);
        }

        #region BOM
        public Bom GetBom(string instanceId)
        {
            return dal.GetBom(instanceId);
        }



        /// <summary>
        /// 获取全部BOM
        /// </summary>
        /// <returns></returns>
        public List<Bom> GetBoms()
        {
            return dal.GetBoms();
        }
        /// <summary>
        /// 根据产品代码获取产品的所有版本的BOM
        /// </summary>
        /// <param name="prodCode">产品代码</param>
        /// <returns></returns>
        public List<Bom> GetBoms(string prodCode)
        {
            FormTlpInfo formTlp = dal.GetFormTemplate("BOM单");//拿到BOM单的模板，以拿到产品物料编码字段的ID            
            string fieldId = formTlp.Fields.Find(f => f.Caption == "产品编码").Id;
            FormFilter[] filter = new FormFilter[1];
            filter[0] = new FormFilter
            {//构造搜索过滤器

                Id = fieldId,
                Operator = "=",
                Value1 = prodCode
            };
            return dal.GetBoms(filter);//带条件搜索，并返回BOM清单
        }
        /// <summary>
        /// 反查含有某物料的所有BOM
        /// </summary>
        /// <param name="itemcode">物料代码</param>
        /// <returns></returns>
        public List<BomPegging> GetBomsByMaterial(string itemcode)
        {
            #region 子表的内容不能通过filter查询到，所以不能通过查询表单信息反查用物料的BOM
            //FormTlpInfo formTlp = dal.GetFormTemplate("BOM单");//拿到BOM单的模板，以拿到产品物料编码字段的ID   
            ////var formField= formTlp.Fields.Find(f => f.Caption == "物料清单-物料编码");失败：无法查询子表字段
            //string fieldId = formField.Id;
            //FormFilter[] filter = new FormFilter[1];
            //filter[0] = new FormFilter
            //{//构造搜索过滤器

            //    Id = fieldId,
            //    Operator = "=",
            //    Value1 = itemcode
            //};
            //return dal.GetBoms(filter);//带条件搜索，并返回BOM清单 
            #endregion
            //ReportTplDetail reportTpl = dal.GetReportTemplate("BOM反查");
            #region 过滤条件：成功！2019-2-5
            ReportFilter[] filter = new ReportFilter[1];
            filter[0] = new ReportFilter
            {//构造搜索过滤器
                Name = "物料编码",
                Operator = "=",
                DestValue = itemcode
            };
            #endregion
            BomPeggingReport rep = reportBLL.BomPegging(filter);
            List<BomPegging> boms = new List<BomPegging>();
            if (rep != null)
            {
                boms = rep.ToBomPeggings();
            }
            return boms;
        }

        /// <summary>
        /// 修复BOM单中的物料信息：
        /// 将BOM单的物料信息（名称、型号、规格）重新从产品信息表更新过来。
        /// 某些使用比如：更新了零部件信息后，如果需要同步更新某些BOM单中的材料属性，可使用此函数
        /// </summary>
        /// <param name="bom"></param>        
        public bool FixBomMaterials(Bom bom)
        {
            return dal.UpdateBom(bom);
        }
        /// <summary>
        /// 修复BOM的产品信息
        /// 功能：根据BOM的产品编码，从产品信息表中提取产品信息，同步给BOM的产品信息，主要是名称、型号、规格几个字段
        /// </summary>
        /// <param name="bom"></param>
        /// <returns></returns>
        public bool FixBomProduct(Bom bom)
        {

            return dal.UpdateBom(bom);
        }
        #endregion

        #region PMC
        /// <summary>
        /// 看看指定受订单和产品是否已经做过PMC计划
        /// </summary>
        /// <param name="soNo"></param>
        /// <returns></returns>
        public bool AlreadyPMC(string soNo, string itemCode)
        {
            List<Pmc> list = dal.GetPmc(soNo);
            bool ans = false;
            foreach (var pmc in list)
            {
                foreach (var p in pmc.Products)
                {
                    if (p.ItemCode == itemCode) ans = true;
                }
            }
            return ans;
        }
        public bool CreatePmcForm(IEnumerable<PmcMaterial> pmcMeterials, IEnumerable<PmcProduct> products, string planner)
        {
            string soNo = "";
            var so = products.Select(p => p.SoNo).Distinct();
            foreach (var s in so)
            {
                soNo += "," + s;
            }
            Pmc pmc = new Pmc()
            {
                Products = products.Distinct().ToList(),
                Materials = pmcMeterials.ToList(),
                Planner = planner,
                CreateDate = DateTime.Now,
                SoNo = soNo.Substring(1)

            };
            return dal.CreatePmc(pmc, out string instId);
        }
        /// <summary>
        /// PMC主程序。
        /// 将输入的产品代码分解成需求清单，包括制造需求、委外需求、和采购需求
        /// </summary>
        /// <param name="reportBLL">用来查产品信息和BOM信息的报表业务类</param>
        /// <param name="itemCode">产品编码，可以是产成品或半成品</param>
        /// <param name="parentItemCode">父产品代码。如果是产成品，则与itemCode相同</param>
        /// <param name="qty">需求数量</param>
        /// <param name="soNo">关联销售订单</param>
        /// <param name="version">BOM版本</param>
        /// <param name="pmcMeterials">存放分解物料的收集器</param>
        /// <returns></returns>
        public void DoPMC(string itemCode, string parentItemCode, double qty, string soNo, ref System.ComponentModel.BindingList<PmcMaterial> pmcMeterials, double version = 1)
        {//1.查BOM。2. 主物料如果是自产、委外、外购，则加一条物料需求 
         //3.如果是自产或委外，则展开下级物料，递归调用本方法

            ProductInfo product = reportBLL.GetProductInfo(itemCode);
            double stockQty = reportBLL.GetStock(product.ItemCode);//查询库存数量
            double tranmitQty = reportBLL.GetTransitQty(product.ItemCode);
            double lockQty = reportBLL.GetLockedQty(product.ItemCode);
            var mat = new PmcMaterial(product, qty, soNo, parentItemCode, stockQty, tranmitQty, lockQty);
            if (mat.PlanningQty > 0)
            {//净需求大于0才进入计划
                if (product.Origin == EOrigin.自产 || product.Origin == EOrigin.委外)
                {//加入一条自产和委外需求，并递归查询下级BOM
                    pmcMeterials.Add(mat);
                    List<BomReportTpl> bom = reportBLL.GetBoms(itemCode, version);
                    if (bom != null)
                    {
                        foreach (var m in bom)
                        {
                            DoPMC(m.ItemCode, m.PrdItemCode, m.Qty * qty, soNo, ref pmcMeterials, m.Version);
                        }
                    }
                    else
                    {
                        ErrMsg += $"找不到 {itemCode} 的版本为 {version} ,标识为 {product.Origin} 的BOM，该项未分解！";
                    }
                }
                else if (product.Origin == EOrigin.外购)
                {
                    pmcMeterials.Add(mat);//加入一条外购需求
                }
            }
            else
            {
                ErrMsg += ";" + itemCode + "库存充足";
            }
            //if (string.IsNullOrEmpty(ErrMsg)) ErrMsg = "OK";//
        } 
        #endregion
    }
}
